
using ContractDocumentation;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Shapes;
using System.Windows.Documents;


namespace ContractDocumentation
{
    class ComplexTypeVisualizer
    {
        static XNamespace xs = "http://www.w3.org/2001/XMLSchema";

        internal static IEnumerable<FrameworkElement> VisualizeComplexType(Context context, XElement complexTypeElement)
        {
            FrameworkElement nameElement = null;
            if (complexTypeElement.Attribute("name") != null)
            {
                nameElement = VisualizeComplexTypeDeclaration(context, complexTypeElement);
            }
            var children = VisualizeComplexTypeContent(context, complexTypeElement);
            if (nameElement != null)
            {
                return UIUtils.LayoutChildren(context, nameElement, children);
            }
            else
            {
                return children;
            }
        }

        static IEnumerable<FrameworkElement> VisualizeComplexTypeContent(Context context, XElement complexTypeElement)
        {
            var children = new List<FrameworkElement>();
            XName complexTypeName = XmlUtils.GetXName(complexTypeElement, (string)complexTypeElement.Attribute("name"));
            if (complexTypeElement.Element(xs + "simpleContent") != null)
            {
                if (complexTypeElement.Element(xs + "simpleContent").Element(xs + "extension") != null)
                {
                    children.AddRange(AttributeVisualizer.VisualizeAttributes(context, complexTypeElement.Element(xs + "simpleContent").Element(xs + "extension")));
                }
            }
            else if (complexTypeElement.Element(xs + "complexContent") != null)
            {
                if (complexTypeElement.Element(xs + "complexContent").Element(xs + "extension") != null)
                {
                    XElement extensionElement = complexTypeElement.Element(xs + "complexContent").Element(xs + "extension");
                    XName baseTypeName = XmlUtils.GetXName(complexTypeElement, (string)extensionElement.Attribute("base"));
                    XElement baseTypeElement = XmlUtils.GetComplexTypeDefinition(context, baseTypeName);

                    if (baseTypeElement != null)
                    {
                        Context subContext = context.SubContext();
                        subContext.VisualizerMode = VisualizerMode.Inherited;
                        children.AddRange(VisualizeComplexTypeContent(subContext, baseTypeElement));
                    }
                    else Console.WriteLine(String.Format("Cannot find definition for complexType '{0}'", baseTypeName));

                    children.AddRange(VisualizeComplexTypeOwnContent(context, extensionElement, complexTypeName));
                }
            }
            else
            {
                children.AddRange(VisualizeComplexTypeOwnContent(context, complexTypeElement, complexTypeName));
            }
            return children;
        }

        static IEnumerable<FrameworkElement> VisualizeComplexTypeOwnContent(Context context, XElement element, XName complexTypeName)
        {
            var ownChildren = new List<FrameworkElement>();
            ownChildren.AddRange(AttributeVisualizer.VisualizeAttributes(context, element));
            ownChildren.AddRange(GroupVisualizer.VisualizeGroupContent(context, element));
            if (context.VisualizerMode == VisualizerMode.Inherited && ownChildren.Count > 0)
            {
                Grid grid = new Grid();
                Rectangle rectangle = new Rectangle()
                {
                    Fill = Brushes.GhostWhite,
                    Stroke = Brushes.Gray,
                    StrokeThickness = 0.5,
                };
                grid.Children.Add(rectangle);
                StackPanel stackPanel = new StackPanel()
                {
                    Margin = new Thickness(0, Visualizer.VerticalGap, Visualizer.HorizontalGap, 0),
                };
                grid.Children.Add(stackPanel);
                FrameworkElement child = UIUtils.LayoutChildren(context, new Ellipse(), ownChildren).Single();
                child.HorizontalAlignment = HorizontalAlignment.Left;
                stackPanel.Children.Add(child);
                TextBlock textBlock = new TextBlock()
                {
                    Text = "inherited from " + complexTypeName,
                    Margin = new Thickness(8, Visualizer.VerticalGap, 0, 4),
                };
                stackPanel.Children.Add(textBlock);

                grid.Tag = new VisualizerTag()
                {
                    GetLeftConnectionPoint = () => new Point(0, Visualizer.VerticalGap + UIUtils.GetLeftConnectionPoint(child).Y),
                    GetRightConnectionPoint = () => new Point(stackPanel.DesiredSize.Width, Visualizer.VerticalGap + UIUtils.GetLeftConnectionPoint(child).Y),
                };
                return new FrameworkElement[] { grid };
            }
            else
            {
                return ownChildren;
            }
        }

        static FrameworkElement VisualizeComplexTypeDeclaration(Context context, XElement complexTypeElement)
        {
            string complexTypeName = (string)complexTypeElement.Attribute("name");
            var q = from complexContentElement in complexTypeElement.Elements(xs + "complexContent")
                    from extensionElement1 in complexContentElement.Elements(xs + "extension")
                    select extensionElement1;
            XElement extensionElement = q.FirstOrDefault();

            Grid grid = new Grid();
            Rectangle rectangle = new Rectangle()
            {
                Fill = Brushes.LightYellow,
                Stroke = Brushes.Black,
                StrokeThickness = 1,
                StrokeDashOffset = 2.5,
                StrokeDashCap = PenLineCap.Round,
                StrokeLineJoin = PenLineJoin.Round,
            };
            grid.Children.Add(rectangle);

            TextBlock textBlock = new TextBlock();
            textBlock.Style = (Style)context.ResourceDictionary["ComplexTypeTextBlock"];
            grid.Children.Add(textBlock);
            Bold complexTypeNameBold = new Bold();
            complexTypeNameBold.Inlines.Add(complexTypeName);
            textBlock.Inlines.Add(complexTypeNameBold);
            if (extensionElement != null)
            {
                textBlock.Inlines.Add(new LineBreak());
                string parent = XmlUtils.GetXName(extensionElement, (string)extensionElement.Attribute("base")).LocalName;
                textBlock.Inlines.Add("extension of " + parent);
            }

            grid.Measure(new Size(Double.PositiveInfinity, Double.PositiveInfinity));
            return UIUtils.AppendDocumentation(context, grid, XmlUtils.GetXsDocumentation(complexTypeElement),
                Math.Max(grid.DesiredSize.Width, 192));
        }
    }
}
